package com.sss.cn.util;

import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/**
 * redis单点缓存,后期扩展切片集群封装
 * @description 
 * @author Dylan Tao
 * @date 2015-11-12 04:20
 * Copyright 2015 bigaka.com. All Rights Reserved.
 */

//@Component("redisCache")
public class RedisCache implements InitializingBean{
	
	private static final Log log = LogFactory.getLog(RedisCache.class);
	
	static final String STATE_OK = "OK";
	
	@Value("#{config['redis.host']}")
	public String host;
	@Value("#{config['redis.port']}")
	private Integer port;
	@Value("#{config['redis.pass']}")
	private String pass;
	@Value("#{config['redis.maxIdle']}")
	private Integer maxIdle;
	@Value("#{config['redis.maxTotal']}")
	private Integer maxTotal;
	@Value("#{config['redis.testOnBorrow']}")
	private Boolean testOnBorrow;
	@Value("#{config['redis.testOnReturn']}")
	private Boolean restOnReturn;
	@Value("#{config['redis.connTimeOut']}")
	private Integer connTimeOut;
	
	private JedisPoolConfig config;
	
	private JedisPool jedisPool;

	@Override
	public void afterPropertiesSet() throws Exception {
		if(StringUtil.isNotEmpty(host) && port > 0 && StringUtil.isNotEmpty(pass)){
			config = new JedisPoolConfig();
			config.setMaxIdle(maxIdle);
		    config.setMaxTotal(maxTotal);
		    config.setTestOnBorrow(testOnBorrow);
		    config.setTestOnReturn(restOnReturn);
		    jedisPool = new JedisPool(config, host, port, connTimeOut, pass);
		}else{
			log.error("redis basic param can not be null,jedis pool init failed!");
		}
	}
	
//  =============== String类型的操作 ================
	
	/**
	 * 放置String json
	 * 存在则覆盖
	 * @param key
	 * @param value
	 */
	public boolean putStr(String key, String value){
		final Jedis jedis = this.getResource();
		try {
			return jedis.set(key, value).equals(STATE_OK);
		}catch (Exception e) {
			log.error(e);
		}finally {
			this.closeResource(jedis);
		}
		return false;
	}
	
	/**
	 * 放置String
	 * 存在则不覆盖
	 * @param key
	 * @param value
	 */
	public boolean putStrCheck(String key, String value){
		final Jedis jedis = this.getResource();
		try {
			if(!jedis.exists(key)){
				return STATE_OK.equals(jedis.set(key, value));
			}else{
				log.info(key + " has exist! putString failed!");
			}
		}catch (Exception e) {
			log.error(e);
		}finally {
			this.closeResource(jedis);
		}
		return false;
	}
	
	/**
	 * 放置String和存放有效期
	 * 存在则覆盖
	 * @param key
	 * @param value
	 * @param seconds 秒
	 * @return
	 */
	public boolean putStrExpire(String key, String value, int seconds){
		final Jedis jedis = this.getResource();
		try {
			return STATE_OK.equals(jedis.setex(key, seconds,value));
		} catch (Exception e) {
			log.error(e);
		}finally {
			this.closeResource(jedis);
		}
		return false;
	} 
	
	public Long getStrExpire(String key){
		final Jedis jedis = this.getResource();
		return jedis.ttl(key);
	}
	
	/**
	 * 放置String/Object json和存放有效期
	 * 存在则不覆盖
	 * @param key
	 * @param value
	 * @param seconds 秒
	 * @return
	 */
	public boolean putStrExpireCheck(String key, String value, int seconds){
		final Jedis jedis = this.getResource();
		try {
			if(!jedis.exists(key)){
				return STATE_OK.equals(jedis.setex(key, seconds,value));
			}else{
				log.info(key + " has exist! putStrExpireCheck failed!");
			}
		}catch (Exception e) {
			log.error(e);
		} finally {
			this.closeResource(jedis);
		}
		return false;
	} 
	
	/**
	 * 获取指定key的值
	 * @param key
	 * @return
	 */
	public String getString(String key){
		final Jedis jedis = this.getResource();
		try {
			return jedis.get(key);
		} catch (Exception e) {
			log.error(e);
		}finally {
			this.closeResource(jedis);
		}
		return null;
	}
	
	/**
	 * 在原来的value上追加str
	 * @param key
	 * @param str
	 * @return
	 */
	public boolean appendString(String key, String str){
		final Jedis jedis = this.getResource();
		try {
			return jedis.append(key, str)==str.length()?false:true;
		} catch (Exception e) {
			log.error(e);
		}finally {
			this.closeResource(jedis);
		}
		return false;
	}  
	
	/**
	 * 在原来的value指定位置上替换为str
	 * @param key
	 * @param str
	 * @return
	 */
	public boolean replaceString(String key, String str,int index){
		final Jedis jedis = this.getResource();
		try {
			return jedis.setrange(key, index, str)==(index + str.length())?true:false;
		} catch (Exception e) {
			log.error(e);
		}finally {
			this.closeResource(jedis);
		}
		return false;
	}  
	
	/**
	 * 在原来的value在开始和结束位置进行截断
	 * @param key
	 * @param str
	 * @return
	 */
	public String subString(String key, int start, int end){
		final Jedis jedis = this.getResource();
		try {
			return jedis.substr(key, start, end);
		} catch (Exception e) {
			log.error(e);
		}finally {
			this.closeResource(jedis);
		}
		return null;
	} 
	
	/**
	 * 是否存在此key
	 * @param key
	 * @return
	 */
	public boolean isExist(String key){
		final Jedis jedis = this.getResource();
		try {
			return jedis.exists(key);
		} catch (Exception e) {
			log.error(e);
		}finally {
			this.closeResource(jedis);
		}
		return false;
	}  
	
//	public boolean batchPutString(HashMap<String, String> keyValue){
//		String[] strs = new String[keyValue.size()*2];
//		Iterator<Entry<String, String>> entryIt = keyValue.entrySet().iterator();
//		while(entryIt.hasNext()){
//			Entry<String, String> entry = entryIt.next();
//			strs[]
//			entry.getKey();
//			entry.getValue();
//		}
//	}
	
	/**
	 * 批量获取指定key集合的对应集合值
	 * @param key
	 * @return 返回nil则表示该key不存在
	 */
	public List<String> batchGetString(String... keys){
		final Jedis jedis = this.getResource();
		try {
			return jedis.mget(keys);
		} catch (Exception e) {
			log.error(e);
		}finally {
			this.closeResource(jedis);
		}
		return null;
	}
	
	/**
	 * 批量移除[只能删除value为String类型的]
	 * @param keys
	 * @return
	 */
	public boolean batchRmString(String... keys){
		final Jedis jedis = this.getResource();
		try {
			return jedis.del(keys)==keys.length?true:false;
		} catch (Exception e) {
			log.error(e);
		}finally {
			this.closeResource(jedis);
		}
		return false;
	}  
	/**
	 * 计数 ++
	 * @param key
	 * @param num
	 * @return
	 */
	public Long incrBy(String key,Long num){
		final Jedis jedis = this.getResource();
		try {
			return jedis.incrBy(key, num);
		}catch (Exception e) {
			log.error(e);
		} finally {
			this.closeResource(jedis);
		}
		return 0L;
		
	}
	/**
	 * 计数 --
	 * @param key
	 * @param num
	 * @return
	 */
	public Long decrBy(String key,Long num){
		final Jedis jedis = this.getResource();
		try {
			return jedis.decrBy(key, num);
		}catch (Exception e) {
			log.error(e);
		} finally {
			this.closeResource(jedis);
		}
		return 0L;
	}
	
//  =============== Object类型的操作 ================
	
	/**
	 * 存放value为非String的任意类型的值
	 * @param key
	 * @param obj
	 * @return
	 */
	public boolean putObject(Object key, Object obj){
		final Jedis jedis = this.getResource();
		try {
			return jedis.set(SerializeUtil.serialize(key), SerializeUtil.serialize(obj)).equals(STATE_OK);
		}catch (Exception e) {
			log.error(e);
		}finally {
			this.closeResource(jedis);
		}
		return false;
	}
	/**
	 * 获取value为非String的任意类型的值
	 * @param key
	 * @return
	 */
	public <T> T getObject(Object key){		
		final Jedis jedis = this.getResource();
		try {
			byte[] value = jedis.get(SerializeUtil.serialize(key));
			if(value == null) return null;
			Object obj = SerializeUtil.unserialize(value);
			return (T)obj;
		}catch (Exception e) {
			log.error(e);
		}finally {
			this.closeResource(jedis);
		}
		return null;
	}
	/**
	 * 移除value为非String的任意类型的值
	 * @param key
	 * @return
	 */
	public boolean rmObject(String key){
		final Jedis jedis = this.getResource();
		try {
			return jedis.del(SerializeUtil.serialize(key))==1?true:false;
		}catch (Exception e) {
			log.error(e);
		}finally {
			this.closeResource(jedis);
		}
		return false;
	}  
	
	/**
	 * 设置指定key的过期时间
	 * @param key
	 * @param seconds 秒
	 * @return
	 */
	public boolean setExpire(Object key,int seconds){
		final Jedis jedis = this.getResource();
		try {
			return jedis.expire(SerializeUtil.serialize(key), seconds)==1?true:false;
		}catch (Exception e) {
			log.error(e);
		}finally {
			this.closeResource(jedis);
		}
		return false;
	}
	
//  =============== List类型的操作 ================
	
	/**
	 * 往指定key的List结构中头部存放value[非String类型的任意类型]
	 * @param key
	 * @param value
	 * @return
	 */
	public boolean putListHeadValue(Object key, Object value){
		return this.lpush(SerializeUtil.serialize(key), SerializeUtil.serialize(value))==1?true:false;
	}
	
	/**
	 * 往指定key的list结构头部存放String或String数组
	 * @param key
	 * @param value
	 * @return
	 */
	public boolean putListHeadValue(String key, String... value){
		final Jedis jedis = this.getResource();
		try {
			return jedis.lpush(key, value)==1?true:false;
		}catch (Exception e) {
			log.error(e);
		}finally {
			this.closeResource(jedis);
		}
		return false;
	}
	
	/**
	 * 往指定key的List结构中头部存放value[非String类型的任意类型]
	 * @param key
	 * @param value
	 * @return
	 */
	public boolean putListFootValue(Object key, Object value){
		return this.rpush(SerializeUtil.serialize(key), SerializeUtil.serialize(value))==1?true:false;
	}
	
	/**
	 * 往指定key的list结构头部存放String或String数组
	 * @param key
	 * @param value
	 * @return
	 */
	public boolean putListFootValue(String key, String... value){
		final Jedis jedis = this.getResource();
		try {
			return jedis.rpush(key, value)==1?true:false;
		}catch (Exception e) {
			log.error(e);
		}finally {
			this.closeResource(jedis);
		}
		return false;
	}
	
	
	/**
	 * 获取指定key的List中指定value[String类型]
	 * @param key
	 * @param index 0第一个元素，1第二个元素，-1表示最后一个元素，-2指倒数第二个
	 * @return
	 */
	public String getListValue(String key, long index){
		final Jedis jedis = this.getResource();
		try {
			return jedis.lindex(key, index);
		}catch (Exception e) {
			log.error(e);
		}finally {
			this.closeResource(jedis);
		}
		return null;
	}
	/**
	 * 获取指定key的List中指定value[非String类型的任意类型]
	 * @param key
	 * @param index  0第一个元素，1第二个元素，-1表示最后一个元素，-2指倒数第二个
	 * @return
	 */
	public Object getListValue(Object key, long index){
		final Jedis jedis =  this.getResource();
		try {
			byte[] bytes = jedis.lindex(SerializeUtil.serialize(key), index);
			return SerializeUtil.unserialize(bytes);
		} catch (Exception e) {
			log.error(e);
		}finally {
			this.closeResource(jedis);
		}
		return null;
	}
	/**
	 * 移除List中value为非String类型的元素
	 * @param key
	 * @return 返回删除的元素
	 */
	public Object rmListValue(Object key){
		return SerializeUtil.unserialize(this.lpop(SerializeUtil.serialize(key)));
	}
	
	/**
	 * 移除List的头部删除value为String类型的元素
	 * @param key
	 * @return 返回删除的元素
	 */
	public String rmListValue(String key){
		final Jedis jedis = this.getResource();
		try {
			return jedis.lpop(key);
		} catch (Exception e) {
			log.error(e);
		}finally {
			this.closeResource(jedis);
		}
		return null;
	}
	
	/**
	 * list从start到end的新集合,T为非String类型的任意对象
	 * @param key
	 * @param start
	 * @param end
	 * @return
	 */
	public List<byte[]> subListValue(Object key, int start, int end){
		final Jedis jedis = this.getResource();
		try {
			return jedis.lrange(SerializeUtil.serialize(key), start, end);
		}catch (Exception e) {
			log.error(e);
		}finally {
			this.closeResource(jedis);
		}
		return null;
	}
	
	/**
	 * list从start到end的新集合,T为String类型
	 * @param key
	 * @param start
	 * @param end
	 * @return
	 */
	public List<String> subListValue(String key, long start, long end){
		final Jedis jedis = this.getResource();
		try {
			return jedis.lrange(key, start, end);
		}catch (Exception e) {
			log.error(e);
		}finally {
			this.closeResource(jedis);
		}
		return null;
	}
	
	 /** 
     * 保留List中start与end之间的value记录 
     * @param Object key 
     * @param int start 记录的开始位置(0表示第一条记录) 
     * @param int end 记录的结束位置（如果为-1则表示最后一个，-2，-3以此类推） 
     * @return 执行状态码 
     * */ 
	public String rmListValue(Object key, int start, int end){
		final Jedis jedis = this.getResource();
		try {
			return jedis.ltrim(SerializeUtil.serialize(key), start, end);
		}catch (Exception e) {
			log.error(e);
		}finally {
			this.closeResource(jedis);
		}
		return null;
	}
	
	 /** 
     * 保留List中start与end之间的value记录 
     * @param String key 
     * @param int start 记录的开始位置(0表示第一条记录) 
     * @param int end 记录的结束位置（如果为-1则表示最后一个，-2，-3以此类推） 
     * @return 执行状态码 
     * */ 
	public String rmListValue(String key, int start, int end){
		final Jedis jedis = this.getResource();
		try {
			return jedis.ltrim(key, start, end);
		}catch (Exception e) {
			log.error(e);
		}finally {
			this.closeResource(jedis);
		}
		return null;
	}
	
	/**
	 * 获取指定key下list的长度
	 * @param key
	 * @return
	 */
	public long getListSize(Object key) {
		final Jedis jedis = this.getResource();
		try {
			return jedis.llen(SerializeUtil.serialize(key));
		} catch (Exception e) {
			log.error(e);
		}finally {
			this.closeResource(jedis);
		}
		return 0;
	}
	
	private byte[] lpop(byte[] key){
		final Jedis jedis = this.getResource();
		try {
			return jedis.lpop(key);
		}catch (Exception e) {
			log.error(e);
		} finally {
			this.closeResource(jedis);
		}
		return null;
	}
	
	private Long lpush(byte[] key, byte[] value){
		final Jedis jedis = this.getResource();
		try {
			return jedis.lpush(key, value);
		} catch (Exception e) {
			log.error(e);
		}finally {
			this.closeResource(jedis);
		}
		return null;
		
	}
	
	private Long rpush(byte[] key, byte[] value){
		final Jedis jedis = this.getResource();
		try {
			return jedis.rpush(key, value);
		}catch (Exception e) {
			log.error(e);
		} finally {
			this.closeResource(jedis);
		}
		return null;
	}
	
	
	
	private Jedis getResource(){
		return jedisPool.getResource();
	}
	
    private void closeResource(Jedis jedis) {
    	if (jedis != null) jedis.close();
    }
    
}
